package com.suxin.event.annotations;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Tang
 * @classname ApplicationListenerMethodAdapter
 * @description [  ]
 * @date 2023/2/28 16:46
 */
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {

    private final Method method;

    private final String beanName;

    private final Class<?> clz;

    private AnnotationConfigApplicationContext applicationContext;

    private final List<ResolvableType> resolvableTypeList;

    public ApplicationListenerMethodAdapter(Method method, String beanName, Class<?> clz) {
        this.beanName = beanName;
        this.method = method;
        this.clz = clz;
        final EventListener ann = AnnotationUtils.findAnnotation(method, EventListener.class);
        // 支持的事件class
        this.resolvableTypeList = resolvableEventTypes(method,ann);
    }

    private static List<ResolvableType> resolvableEventTypes(Method method, EventListener ann) {
        List<ResolvableType> resolvableTypes = new ArrayList<>();
        if (ann == null) {
            return resolvableTypes;
        }
        final Class<?>[] classes = ann.classes();
        for (Class<?> aClass : classes) {
            resolvableTypes.add(ResolvableType.forClass(aClass));
        }
        return resolvableTypes;
    }

    public static void main(String[] args) {
        final ResolvableType resolvableType = ResolvableType.forClass(ApplicationListenerMethodAdapter.class);
        System.out.println(resolvableType.getRawClass());
    }

    public void init(AnnotationConfigApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public Object getTargetBean() {
        return this.applicationContext.getBean(this.beanName);
    }

    @Override
    public boolean supportsEventType(ResolvableType resolvableType) {
        for (ResolvableType type : resolvableTypeList) {
            if (type.isAssignableFrom(resolvableType)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        processEvent(event);
    }

    protected void processEvent(ApplicationEvent event) {
        final Object targetBean = getTargetBean();
        try {
            this.method.invoke(targetBean, event);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}